%{
#include <stdio.h>
#include <stdlib.h>
#include <memory>
#include "ast.h"

std::unique_ptr<BaseAST> root; // 语法分析完成后的 AST 根节点
int yydebug = 0;  // 调试标志
int yylex();
void yyerror(const char *s);
%}

%union {
    BaseAST* ast_ptr;    // 指向 AST 节点
    int int_val;         // 整数字面量
    char* str_val;       // 标识符和字符串字面量
}

%token MAIN CONST INT BREAK CONTINUE IF ELSE 
%token WHILE GETINT PRINTF RETURN VOID
%token COMMA SEMICN ASSIGN LPARENT RPARENT LBRACE RBRACE LBRACK RBRACK
%token NOT AND OR PLUS MINU MULT DIV MOD LSS LEQ GRE GEQ EQL NEQ

%left PLUS MINU
%left MULT DIV MOD
%left LSS LEQ GRE GEQ
%left EQL NEQ
%right AND OR
%right NOT

%right UMINUS UPLUS

%token <str_val> IDENT STR_CONST
%token <int_val> INT_CONST

%type <ast_ptr> CompUnit Decl VarDecl FuncDef Expr
%type <ast_ptr> BType MainFuncDef Block BlockItems BlockItem
%type <ast_ptr> Stmt Assignment Number

%%

CompUnit
    : Decl FuncDef FuncDef MainFuncDef {
        if(yydebug)
        printf("<CompUnit>\n");
        auto ast = std::make_unique<CompUnitAST>();
        ast->decl.reset(static_cast<BaseAST*>($1));
        ast->func_def1.reset(static_cast<BaseAST*>($2));
        ast->func_def2.reset(static_cast<BaseAST*>($3));
        ast->main_func_def.reset(static_cast<BaseAST*>($4));
        root = std::move(ast);  // 设置全局根节点
    }
    ;


Decl :
    VarDecl {
        if(yydebug)
        printf("<Decl>\n");
        auto ast = std::make_unique<DeclAST>();
        ast->decl.reset(static_cast<BaseAST*>($1));
        ast->kind = DeclAST::DeclKind::VAR_DECL;
        $$ = ast.release();
    }
    ; 
    

FuncDef :
    BType IDENT LPARENT BType IDENT RPARENT Block {
        if(yydebug)
        printf("<FuncDef>\n");
        auto ast = std::make_unique<FuncDefAST>();
        ast->type = TYPE_INT;
        ast->ident = std::string($2);
        free($2);
        ast->param_type = TYPE_INT;
        ast->param_ident = std::string($5);
        free($5);
        ast->block.reset(static_cast<BaseAST*>($7));
        $$ = ast.release();
    }
    ;


MainFuncDef :
    INT MAIN LPARENT RPARENT Block {
        if(yydebug)
        printf("<MainFuncDef>\n");
        auto ast = std::make_unique<MainFuncDefAST>();
        ast->block.reset(static_cast<BaseAST*>($5));
        $$ = ast.release();
    }
    ;

Block :
    LBRACE BlockItems RBRACE {
        if(yydebug)
        printf("<Block>\n");
        $$ = $2;  // 直接使用BlockItems生成的BlockAST
    }| LBRACE RBRACE {
        auto ast = std::make_unique<BlockAST>();  // 创建空块
        $$ = ast.release();
    }
    ;



BlockItems :
    BlockItems BlockItem {
        auto block = dynamic_cast<BlockAST*>($1);
        if (block && $2) {
            block->items.emplace_back(static_cast<BaseAST*>($2));
        }
        $$ = block;
    } | BlockItem {
        auto ast = std::make_unique<BlockAST>();
        if ($1) {
            ast->items.emplace_back(static_cast<BaseAST*>($1));
        }
        $$ = ast.release();
    }
    ;

BlockItem :
    Decl {
        // 处理 BlockItem
         if(yydebug)
        printf("In BlockItem\n");
        $$ = $1;
    }
    | Stmt {
        $$ = $1;
    }
    ;

Stmt :
    Assignment SEMICN {
        auto ast = std::make_unique<StmtAST>();
        ast->kind = StmtAST::ASSIGNMENT;
        ast->content.reset(static_cast<BaseAST*>($1));
        $$ = ast.release();
    }
    | Block {
        auto ast = std::make_unique<StmtAST>();
        ast->kind = StmtAST::BLOCK;
        ast->content.reset(static_cast<BaseAST*>($1));
        $$ = ast.release();
    }
    | RETURN Number SEMICN {
        auto ast = std::make_unique<StmtAST>();
        ast->kind = StmtAST::RETURN;
         // 获取Number节点的值
        auto number = dynamic_cast<NumberAST*>($2);
        if (number) {
            ast->return_num = number->value;
        }
                
        $$ = ast.release();
    }
    | SEMICN {
        auto ast = std::make_unique<StmtAST>();
        ast->kind = StmtAST::EMPTY;
        $$ = ast.release();
    }
    | IF LPARENT Expr RPARENT Stmt{
        auto if_stmt = new StmtAST();
        if_stmt->kind = StmtAST::IF;
        if_stmt->condition.reset(static_cast<ExprAST*>($3));
        if_stmt->if_branch.reset(static_cast<StmtAST*>($5));
        
        $$ = if_stmt;
    }
    | IF LPARENT Expr RPARENT Stmt ELSE Stmt{
        auto if_stmt = new StmtAST();
        if_stmt->kind = StmtAST::IF;
        if_stmt->condition.reset(static_cast<ExprAST*>($3));
        if_stmt->if_branch.reset(static_cast<StmtAST*>($5));
        if_stmt->else_branch.reset(static_cast<StmtAST*>($7));
        
        
        $$ = if_stmt;
    }
    | PRINTF LPARENT STR_CONST RPARENT SEMICN{
        auto ast = std::make_unique<StmtAST>();
        ast->kind = StmtAST::PRINTF;
        ast->str = std::string($3);
        free($3);
        $$ = ast.release();
    }
    | PRINTF LPARENT STR_CONST COMMA IDENT RPARENT SEMICN{
        auto ast = std::make_unique<StmtAST>();
        ast->kind = StmtAST::PRINTF;
        ast->str = std::string($3);
        free($3);
        ast->ident = std::string($5);
        free($5);
        $$ = ast.release();
    }
    ;

Expr :
    Expr AND Expr {
        auto ast = new BinaryExprAST();
        ast->left.reset(static_cast<ExprAST*>($1));
        ast->right.reset(static_cast<ExprAST*>($3));
        ast->op = "&&";
        $$ = ast;
    }
    | Expr LEQ Expr {
        auto ast = new BinaryExprAST();
        ast->left.reset(static_cast<ExprAST*>($1));
        ast->right.reset(static_cast<ExprAST*>($3));
        ast->op = "<=";
        $$ = ast;
    }
    | Expr GRE Expr {
        auto ast = new BinaryExprAST();
        ast->left.reset(static_cast<ExprAST*>($1));
        ast->right.reset(static_cast<ExprAST*>($3));
        ast->op = ">";
        $$ = ast;
    }
    | Expr GEQ Expr {
        auto ast = new BinaryExprAST();
        ast->left.reset(static_cast<ExprAST*>($1));
        ast->right.reset(static_cast<ExprAST*>($3));
        ast->op = ">=";
        $$ = ast;
    }
    | Expr LSS Expr {
        auto ast = new BinaryExprAST();
        ast->left.reset(static_cast<ExprAST*>($1));
        ast->right.reset(static_cast<ExprAST*>($3));
        ast->op = "<";
        $$ = ast;
    }
    | Expr OR Expr {
        auto ast = new BinaryExprAST();
        ast->left.reset(static_cast<ExprAST*>($1));
        ast->right.reset(static_cast<ExprAST*>($3));
        ast->op = "||";
        $$ = ast;
    }
    | NOT Expr {
        auto ast = new UnaryExprAST();
        ast->operand.reset(static_cast<ExprAST*>($2));
        ast->op = "!";
        $$ = ast;
    }
    | IDENT {
        $$ = new IdentExprAST($1);
    }
    | IDENT LPARENT Expr RPARENT {
        auto func_call = new FunctionCallExprAST($1);
        func_call->args.emplace_back(static_cast<ExprAST*>($3));
        $$ = func_call;
    }
    | LPARENT Expr RPARENT {
        $$ = $2;  // 去掉括号，直接使用内部表达式
    }
    ;

Assignment :
    IDENT ASSIGN GETINT LPARENT RPARENT {
        auto ast = std::make_unique<AssignmentAST>();
        ast->ident = std::string($1);
        ast->is_getint = true;
        // 释放字符串
        free($1);
        
        $$ = ast.release();
    }
    | IDENT ASSIGN IDENT {
        auto ast = std::make_unique<AssignmentAST>();
        ast->ident = std::string($1);
        ast->ident_r = std::string($3);
        // 释放字符串
        free($1);
        free($3);
        
        $$ = ast.release();
    }
    | IDENT ASSIGN Number {
        auto ast = std::make_unique<AssignmentAST>();
        ast->ident = std::string($1);
        // 释放字符串
        free($1);
         // 获取Number节点的值
        auto number = dynamic_cast<NumberAST*>($3);
        if (number) {
            ast->num = number->value;
        }
        $$ = ast.release();
    }
    ;

VarDecl :
    BType IDENT SEMICN{
        if(yydebug)
        printf("<VarDecl>\n");
        auto ast = std::make_unique<VarDeclAST>();
        ast->type = TYPE_INT;
        ast->ident = std::string($2);
        
        // 释放字符串
        free($2);
        
        $$ = ast.release();
    }
    | BType IDENT ASSIGN Number SEMICN {
         auto ast = std::make_unique<VarDeclAST>();
        ast->type = TYPE_INT;
        ast->ident = std::string($2);
        
        // 释放字符串
        free($2);
        
        $$ = ast.release();
    }
    ;

BType : 
    INT {
        // 处理 BType
    }
    ;

Number :
    INT_CONST {
        auto ast = std::make_unique<NumberAST>();
        ast->value = $1;
        $$ = ast.release();
    }
    ;

%%

void yyerror(const char *s){
    printf("error:%s\n",s);
}